home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Chip 1996 April
/
CHIP 1996 aprilis (CD06).zip
/
CHIP_CD06.ISO
/
hypertxt.arj
/
9509
/
ART01.CD
< prev
next >
Wrap
Text File
|
1996-03-10
|
15KB
|
268 lines
@VPethô Ådám: Variációk assemblyre@N
@VBemutatás, vagy valami efféle...@N
Hosszú szünet után jelent meg végre a PC assembly
programozásáról szóló könyvsorozatom 4., utolsó kötete.
Méretre, súlyra, a tárgyalt témakörök számára nézve
egyaránt tekintélyes darab. 480 oldalas terjedelme, és
lemezmellékletének összesen 1,8 Mbyte-nyi példaprogramja
alapján képet alkothatunk errôl. Témája: az assembly
programozás, száznál is több gyakorlati példával
megvilágítva.
A választott és megoldott feladatok az egyszerû
memóriafeltöltéssel kezdôdnek, és bejárva a konverzió, a
keresés és rendezés egyes szép tájait, számos kitérô után
egy soros vonali driverig jutnak (melyhez persze
hardverinterrupt-kezelés, egy time-out csomag és egy C-ben
írt, mûködô file-átviteli program tartozik). Eközben volt
idô például egy ""hosszú egészek aritmetikája" címû
csomagra, amely tetszôlegesen hosszú egészeket többek között
oszt tetszôleges hosszú egészekkel; szerepel a könyvben
néhány ravasz stackelési varázslat, és sok más okosság.
A könyv írása közben három alapvetô gondolatot
igyekeztem szem elôtt tartani. Az elsô, hogy azt a
gondolatmenetet és érvrendszert is megkíséreljem bemutatni,
amelynek alapján egy feladat számtalan lehetséges megoldása
közül kiválasztjuk a legelônyösebbnek tûnôt. A második, hogy
a megvalósítás során a lehetô legtrükkmentesebb,
biztonságos, precíz munkamódszer kialakítására törekedjek. A
harmadik pedig, hogy vessük alá az elkészült rutinokat a
lehetô legalaposabb tesztelésnek -- ne csak higgyük, hanem
lehetôleg bizonyítsuk is: az elkészült programok valóban azt
csinálják, amit állítunk róluk.
A könyvet tartalomjegyzék, tárgymutató és sörzáradék
teszi teljessé. Ez utóbbi (saját lelemény) a következôt
tartalmazza: minden hiba elsô felfedezôje kap tôlem egy
korsó (kitûnô minôségû) seritalt. Ha más nem is, ez -- azt
hiszem -- unikum (persze nem Unicum) az egyébként elég
száraz tematikájú könyvemben. A leggondosabb elôkészítés és
tesztelés dacára a sörmeghívás nem irreális: az
utómunkálatok során magam is találtam már több mint tíz
hibát (ezekre a meghívás természetesen vonatkozik). A
hibajelzéseket az 1615 Budapest, Pf. 217. címre, Pethô Ådám
névre kérem.
A könyv egyébként megvásárolható a ComputerTalum Press
irodájában: Budapest, Váci út 202. III/328., tel./fax:
120-1636 (Szalay Zsóka).
Az alábbi írásban éppen a tesztelés véres küzdelmeibôl
mutatok be egy ""gyöngyszemet". A kiválasztott példa kényes
kis feladat: a bináris keresés.
@VA tesztelésrôl általában@N
A szakirodalom azt írja, hogy a programok tervezésekor
(és nem utána) kell megtervezni a tesztelési eljárásokat.
Ezek sikeres végrehajtása fogja majd igazolni, hogy készen
vagyunk. Nagyon fontos, hogy a konkrét programozás elôtt
elkészüljön az összes tesztprogram és a teszteléshez
szükséges adathalmaz. A programozás ugyanis fárasztó,
ugyanakkor felvillanyozó tevékenység, s ""befejezése" után
az ember ritkán van abban az állapotban, hogy elszántan
kezdjen hozzá a teszteléshez, ráadásul a megvalósítás közben
általában olyan részletkérdésekkel bíbelôdik, amelyek
könnyen elfedik az egyszerûbb (és veszélyesebb)
hibalehetôségeket.
Annak tehát, hogy programozás elôtt és nem utána kell
megtervezni a tesztelést, stratégiai és pszichikai okai
egyaránt vannak. A tesztelés tervezése során fel kell
térképezni minden szóbajöhetô esetet, amelyen a program
értelmesen dolgozhat. Ezen kívül szükség van különleges,
valamint elfajuló esetekre, a program minden egyes
bemenetére nézve. Ennyi a tesztelés elsô fázisa, amit talán
minôségi tesztnek hívhatnánk. Ezután kerülhet sor az
úgynevezett (én ""úgyneveztem" így) mennyiségi tesztre. A
minôségi teszt kevés, de nagyon jól megválogatott
tesztadaton történik -- ha azonban várható, hogy a program
sok és nagyméretû objektumon is fog dolgozni, akkor
generálnunk kell olyan teszt-adathalmazokat, amelyek
megközelítik, sôt, meghaladják azt a maximális méretet,
amelyen a programnak emberi számítás szerint futnia kell.
Bizony, a nagy mennyiségek és méretek váratlan csapdákat
rejthetnek (betelnek bizonyos táblázatok, lemezek, szalagok;
túlcsordulnak számlálók, aritmetikai változók stb.). A
mennyiségi teszt megtervezése éppen akkora gondosságot
igényel, mint a minôségié.
Lehetôség szerint mindkét teszthez olyan adatokat
válasszunk, amelyek jellemzôek, de amelyeknél viszonylag
könnyen kiszámíthatjuk a helyes eredményeket -- és
ügyeljünk, nehogy speciális esetek és matematikai törvények
elfedjék a hibákat stb.
@VA bináris keresésrôl@N
Elôrebocsátom: elsô kísérletre bizony elböktem a keresô
rutint. Pszeudokódban fogom csak bemutatni (nem szívesen
írnék le ide példaprogram gyanánt hibásan mûködô
változatot).
Az eljárás közismert: ha rendezett tömbben keresünk egy
elemet, akkor ránézünk a halmaz közepére. Ha a keresett elem
nagyobb, mint a középsô, akkor a tömb felsô, ha kisebb,
akkor pedig az alsó felén folytatjuk ugyanezt a mûveletet.
Mivel minden lépésben megfelezzük a tömböt, az eljárás véges
sok lépésben befejezôdik, és igen gyorsan megtalálja a
keresett elemet, illetve jelzi, hogy nincs benne a tömbben.
A hiba az volt, hogy ha a szorgos felezgetés közben nem
találtam rá a keresett elemre, akkor -- mivel a pointer most
is mutat valahová -- még ránéztem a tömbre: nem pont a
pointer végállásánál van-e a keresett elem. Ez súlyos
melléfogásnak bizonyult, hiszen amikor a tömbhossz 0 (ez
jelzi a ciklus végét), akkor a változók üres tömböt ""írnak
le". Ekkor pedig már semmiféle mûveletnek nincs helye,
legkevésbé egy ilyen ""sicher was sure" odapislantásnak.
Lássuk a saját magam által kialakított stílusú
pszeudokódban a keresés vázlatát (a hibás változatot):
Bináris keresési eljárás kezdôcím és hossz alapján
Bemenet
pnt a tömb kezdôcíme
size a tömb hossza (elemszáma)
val a keresendô érték
Kimenet:
addr a megtalált elem címe
index a megtalált elem indexe
vagy
hibajelzés (ha a keresett érték nincs a tömbben)
Munkaváltozó:
wpnt mindig a vizsgált tömb kezdôcímét tartalmazza
wsize mindig a vizsgált tömb hosszát tartalmazza
Elôkészítés:
wpnt = pnt
wsize = size
Ciklus:
ha wsize = 0 (a tömb elfogyott) [átgondolatlan pont]
ha wpnt[ 0 ] = val (megvan)
addr = wpnt
index = addr - wpnt
különben (nincs a tömbben)
addr = 0
index = 0
hibajelzés
vége;
ha wpnt[ wsize/2 ] = val (megvan)
addr = wpnt + wsize/2
index = addr - pnt
vége;
ha wpnt[ size/2 ] > val (alsó felén folytatjuk)
wsize = wsize/2
Ciklus-sal folytatjuk;
ha wpnt[ size/2 ] < val (felsô felén folytatjuk)
wpnt = wpnt + wsize/2 + 1
wsize = wsize - wsize/2 - 1
Ciklus-sal folytatjuk;
A szögletes zárójelek között külön kommentezett sor a
bûnös, de lássuk, hogy miben.
@VTesztstratégia a bináris kereséshez@N
Gondoljuk végig a bináris keresés tesztelési
stratégiáját! (Ezt követtem akkor is, amikor egy kedves
barátomnak mutattam a példaprogramot, s miközben
magyaráztam, hogy mindez miért is olyan nagyszerû, kishíján
hanyattestem, mikor egy elfajuló esetet pozitív eredménnyel
zárt a rutin...)
Elsôként vegyük a közönséges eseteket. Ehhez veszünk egy
rendezett tömböt, melyben elôfordul többszörös érték is
(nehogy kihasználjuk véletlenül, hogy az elemek szigorúan
monoton növekvôek). Ezek után elôször keressünk a tömbben
szereplô értékeket: a legelsô, több belsô (közöttük többször
szereplô) és az utolsó (legnagyobb) elem értékét!
A következô lépés ugyanerre a tömbre a tömbben nem
szereplô értéket keresni: kisebbet, mint a tömb elsô eleme,
az elsô és a második közé esôt, két belsô tömbelem közé
esôt, az utolsó elôtti és az utolsó közé esôt, végül olyat,
ami nagyobb az utolsónál is.
Ezután speciális eseteket vizsgálunk: olyan tömböt,
amelynek összes értéke azonos; ne mulasszuk el egyelemû tömb
vizsgálatát sem! Végül egy elfajuló esetet is meg kell
vizsgálni: az üres tömböt, amelynek elemszáma 0.
Maga a keresendô elem, mint egyszerû számérték (ti. az
egészek körében) nem tartogathat semmi meglepetést, erre
tehát nem kell esetszétválasztásokat végeznünk.
Lássuk az adathalmazt!
DATA SEGMENT PARA PUBLIC 'DATA' ;
;
ARRAY1 DW 1, 3, 3, 6, 9, 11, 52, 86
ARRAY1_SIZE EQU ( $ - ARRAY1 ) / TYPE ARRAY1
;
;Speciális eset '1: konstans tömb
ARRAY2 DW 4, 4, 4, 4 ;
ARRAY2_SIZE EQU ( $ - ARRAY2 ) / TYPE ARRAY2
;
;Speciális eset '2: egyelemû tömb
ARRAY3 DW 5 ;
ARRAY3_SIZE EQU ( $ - ARRAY3 ) / TYPE ARRAY3
;
;Elfajuló eset: üres tömb
ARRAY4 LABEL WORD ;
ARRAY4_SIZE EQU 0 ;
;
DATA ENDS ;
A fenti négy tömb lefedi a minôségi teszt közönséges és
speciális eseteit. A rutin tesztelésekor az alábbi értékeket
használtam, mint keresendô értékeket:
(1) az ARRAY1 tömbben kerestem az 1, 3, 6, 11, 52 és 86,
valamint a -5 értékeket (hátha negatívra nem jól mûködik),
majd a 0, 2, 5, 10, 80 és 90 értékeket;
(2) az ARRAY2 tömbben kerestem a 3, 4 és 5 értékeket;
(3) az ARRAY3 ""tömbben" kerestem a 4, 5 és 6 értékeket;
(4) végül az ARRAY4 elfajuló ""tömbben" (ami még csak
nem is létezett) kerestem egy tetszôleges értéket --
konkrétan a 8-at.
A mennyiségi teszt ezúttal elhagyható. A bináris
keresést végrehajtó eljárás megírásakor csak annyit tettünk
fel, hogy a tömb nem haladja meg a szegmensnyi méretet, és a
végigcímezhetô DS szegmensregiszter bemenetkori állásával.
Ha nem így van, a rutin nyilvánvalóan hibázik, ha pedig
teljesül, akkor nem játszik szerepet a tömb mérete, sem a rá
mutató pointerek értéke.
@VAz eredmény@N
Nos, amikor elkészültem a tesztelési stratégiával,
nagyon meg voltam elégedve magammal. Igazán figyelembe
vettem minden számottevô esetet, és jól áttekinthetô,
ugyanakkor egyszerû tesztadatokat hoztam létre.
Ezt hívén, igazán meglepett, hogy az ARRAY2 tömbben
(amely csupa 4 értékbôl áll), a rutin szívfájdalom nélkül
megtalálta az 5 értéket.
Ez annak volt köszönhetô, hogy végiglépegetve-felezgetve
a rendelkezésre álló címtartományt, a munkapointer szorgosan
lépkedett felfelé, és olyan szerencsétlenül álltak a
csillagok, hogy a kilépéskor a pointerben maradt szemét már
a tömbön kívülre mutatott. A tétován az eljárás után küldött
utolsó ellenôrzés tehát már nem a tömb területét vizsgálta.
Ekkor következett programozói pályám egyik legnagyobb
mázlija: ott, ahová a pointer nézett, éppen a keresett, és a
tömbben nem található 5 érték volt a tárban. Nagyon sok
mindennek kellett ehhez így együtt állnia (például a fizikai
tárcímeknek...). Ha ez az elképesztô szerencse nem jön
segítségemre, akkor bizony abban a hitben élnék, hogy a fent
bemutatott pszeudokód helyes.
@VMi ebbôl a tanulság?@N
""Abszolúte semmi". Talán az, hogy szép lehetsz, de okos
nem. Akárkinek meséltem el a tesztstratégiát, azt mondta:
olyan, ahogyan a nagykönyvben meg van írva. Mindenre
gondoltam -- és a vak véletlen mentett meg egy kínos
hibától.
Végeredményben: ha átkozunk egy szoftvert, mert tele van
hibával, gondoljunk az efféle esetekre is. A tesztelés
részben szakma, részben mûvészet. Nyilván mindenki mindent
megtesz, de ha egy hatalmas programrendszer minden egyes
rutinja efféle csapdákat rejteget, akkor tôlünk, akik
nemcsak felhasználók, de talán fejlesztôk is vagyunk,
várható némi megértés.
@KPethô Ådám@N